/***************************************************************************
      File Name:  ConfigurationFile.cs
   File Created:  Monday, July 2nd 2007
      Copyright:  (C) 2007 by Darko Matesic
          Email:  darko.matesic@yahoo.com
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Xml;
using System.IO;
using System.Text;
using System.Windows.Forms;
using CallerID.Helpers;

namespace CallerID
{
    /// <summary>
    /// Class for handling configuration files.
    /// </summary>
    public class ConfigurationFile: IConfigurationFile
    {
        /// <summary>
        /// Private class for storing section key data.
        /// </summary>
        private class Key
        {
            private string m_Name;
            private string m_Value;

            public Key(string name)
            {
                this.m_Name = name;
                this.m_Value = "";
            }
            public string Name
            {
                get { return m_Name; }
            }
            public string Value
            {
                get { return m_Value; }
                set { m_Value = value; }
            }
        }
        /// <summary>
        /// Private class for storing section data.
        /// </summary>
        private class Section
        {
            private string m_Name;
            private List<Key> m_Keys;

            public Section(string name)
            {
                this.m_Name = name;
                this.m_Keys = new List<Key>();
            }
            public string Name
            {
                get { return m_Name; }
            }
            public List<Key> Keys
            {
                get { return m_Keys; }
            }

            /// <summary>
            /// Returns section key with specified key name.
            /// If key does not exist it returns null.
            /// </summary>
            public Key GetKey(string keyName)
            {
                if(keyName != null && keyName.Length > 0) {
                    foreach(Key key in this.m_Keys) {
                        if(key != null && key.Name == keyName) return key;
                    }
                }
                return null;
            }

            /// <summary>
            /// Creates new key with specified key name.
            /// If a key with a givne key name already exists it returns existing key.
            /// </summary>
            public Key CreateKey(string keyName)
            {
                if(keyName != null && keyName.Length > 0) {
                    Key key = GetKey(keyName);
                    if(key == null) {
                        key = new Key(keyName);
                        this.m_Keys.Add(key);
                    }
                    return key;
                }
                return null;
            }

            /// <summary>
            /// Removes a key with specified name from section.
            /// </summary>
            public bool DeleteKey(string keyName)
            {
                Key key = GetKey(keyName);
                if(key != null) {
                    this.m_Keys.Remove(key);
                    return true;
                }
                return false;
            }

            /// <summary>
            /// Clears all data from current section.
            /// </summary>
            public void Clear()
            {
                m_Keys.Clear();
            }

            /// <summary>
            /// Returns names of all keys in current section.
            /// </summary>
            /// <returns>String array of all key names if successful; otherwise, null</returns>
            public string[] GetKeyNames()
            {
                string[] names = new string[this.m_Keys.Count];
                for(int i = 0; i < this.m_Keys.Count; i++) names[i] = this.m_Keys[i].Name;
                return names;
            }
        }

        private List<Section> m_Sections;
        private string m_FileName;
        private bool m_PreventEmptySave = false;
        private bool m_BackupOnSave = true;

        /// <summary>
        /// Returns section with specified section name.
        /// If section does not exist it returns null.
        /// </summary>
        private Section GetSection(string sectionName)
        {
            if(sectionName != null || sectionName.Length > 0) {
                foreach(Section section in this.m_Sections) {
                    if(section != null && section.Name == sectionName) return section;
                }
            }
            return null;
        }

        /// <summary>
        /// Returns section key with specified name in a specifed section.
        /// If key does not exist in specified section it returns null.
        /// </summary>
        private Key GetKey(Section section, string keyName)
        {
            if(section != null) return section.GetKey(keyName);
            return null;
        }


        /// <summary>
        /// Returns key with specified name in a section with specified section name.
        /// If section does not exists or a key does not exist in specified section it returns null.
        /// </summary>
        private Key GetKey(string sectionName, string keyName)
        {
            return GetKey(GetSection(sectionName), keyName);
        }

        /// <summary>
        /// Creates new section with specified section name.
        /// If a section with a givne section name already exists it returns existing section.
        /// </summary>
        private Section CreateSection(string sectionName)
        {
            if(sectionName != null && sectionName.Length > 0) {
                Section section = GetSection(sectionName);
                if(section == null) {
                    section = new Section(sectionName);
                    this.m_Sections.Add(section);
                }
                return section;
            }
            return null;
        }

        /// <summary>
        /// Creates new key with specified key name in specified section.
        /// If a key with a givne key name already exists in specified section it returns existing key.
        /// If section does not exist it returns null.
        /// </summary>
        private Key CreateKey(Section section, string keyName)
        {
            if(section != null && keyName != null && keyName.Length > 0) {
                Key key = section.GetKey(keyName);
                if(key == null) key = section.CreateKey(keyName);
                return key;
            }
            return null;
        }

        /// <summary>
        /// Creates new key with specified key name in a section with specified name.
        /// If a key with a givne key name already exists in specified section it returns existing key.
        /// If section does not exist it returns null.
        /// </summary>
        private Key CreateKey(string sectionName, string keyName)
        {
            return CreateKey(GetSection(sectionName), keyName);
        }

        /// <summary>
        /// Writes a value to a key with specified name in a specified section.
        /// If section does not exist it returns false and value is not written.
        /// If specified key does not exist it will be created.
        /// </summary>
        private bool WriteValue(Section section, string keyName, string value)
        {
            Key key = CreateKey(section, keyName);
            if(key != null) {
                key.Value = value;
                return true;
            }
            return false;
        }

        /// <summary>
        /// Writes a value to a key with specified name in a section with specified name.
        /// If section does not exist it will be created.
        /// If specified key does not exist it will be created.
        /// </summary>
        private bool WriteValue(string sectionName, string keyName, string value)
        {
            return WriteValue(CreateSection(sectionName), keyName, value);
        }

        /// <summary>
        /// Returns total number of keys of all sections
        /// </summary>
        public int GetTotalKeyCount()
        {
            if(m_Sections == null || m_Sections.Count == 0) return 0;
            int count = 0;
            foreach(Section section in m_Sections)
                count += (section.Keys != null ? section.Keys.Count : 0);
            return count;
        }

        /// <summary>
        /// Reads sections and keys from a string.
        /// I does not delete previously created sections and keys but
        /// will overwrite sections or keys with a same name.
        /// String can hold data in ini format or in xml format.
        /// </summary>
        public void ParseText(string text)
        {
            if(text.StartsWith("<?xml")) {
                try {
                    MemoryStream stream = new MemoryStream();
                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(text);
                    stream.Write(buffer, 0, buffer.Length);
                    stream.Flush();
                    stream.Position = 0;
                    XmlTextReader reader = new XmlTextReader(stream);
                    XmlDocument doc = new XmlDocument();
                    doc.Load(reader);
                    if(doc.ChildNodes.Count >= 2) {
                        XmlNode rootNode = doc.ChildNodes.Item(1);
                        for(int i = 0; i < rootNode.ChildNodes.Count; i++) {
                            XmlNode sectionNode = rootNode.ChildNodes.Item(i);
                            Section section = CreateSection(sectionNode.Name.Trim());
                            for(int j = 0; j < sectionNode.ChildNodes.Count; j++) {
                                XmlNode keyNode = sectionNode.ChildNodes.Item(j);
                                WriteValue(section, keyNode.Name.Trim(), StringHelpers.RestoreSpecialCharacters(keyNode.InnerText));
                            }
                        }
                    }
                    reader.Close();
                } catch {
                }
            } else {
                string[] lines = text.Split('\n');
                Section section = null;
                for(int i = 0; i < lines.GetLength(0) - 1; i++) {
                    string line = lines[i];
                    if(line.StartsWith("\r")) line = line.Substring(1);
                    if(line.EndsWith("\r")) line = line.Remove(line.Length - 1);
                    if(line.Length == 0) continue;
                    // skip comments (comments start with # or ')
                    if(line[0] == '#' || line[0] == '\'') continue;
                    // new section ?
                    if(line[0] == '[') {
                        string sectionName = line.Substring(1, line.IndexOf(']') - 1);
                        section = CreateSection(sectionName.Trim());
                        continue;
                    }
                    // find '='
                    int index = line.IndexOf('=');
                    if(section != null && index > 0) {
                        string keyName = line.Substring(0, index);
                        string value = line.Substring(index + 1);
                        WriteValue(section, keyName.Trim(), StringHelpers.RestoreSpecialCharacters(value));
                    }
                }
            }
        }

        /// <summary>
        /// Creates a string that contains data of all sections and keys.
        /// It can create ini or xml formated string.
        /// </summary>
        /// <param name="buildXml">Specifies if output format should be in xml</param>
        /// <param name="indentedXml">If output format is xml this specifies if string should be properly formated for easy reading</param>
        /// <returns>String that contains data of all sections and keys</returns>
        public string BuildText(bool buildXml, bool indentedXml)
        {
            if(buildXml) {
                String xml = "";
                try {
                    MemoryStream stream = new MemoryStream();
                    XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.UTF8);
                    if(indentedXml) writer.Formatting = Formatting.Indented;
                    writer.WriteStartDocument();
                    writer.WriteStartElement("Root");
                    foreach(Section section in m_Sections) {
                        writer.WriteStartElement(section.Name);
                        foreach(Key key in section.Keys) {
                            writer.WriteElementString(key.Name, StringHelpers.EscapeSpecialCharacters(key.Value));
                        }
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                    writer.Flush();
                    int position = (int)stream.Position;
                    writer.Close();
                    xml = System.Text.Encoding.UTF8.GetString(stream.GetBuffer(), 0, position);
                } catch { }
                return xml;
            }
            System.Text.StringBuilder text = new System.Text.StringBuilder();
            foreach(Section section in m_Sections) {
                text.Append("[" + section.Name + "]\r\n");
                foreach(Key key in section.Keys) {
                    text.Append(key.Name + "=" + StringHelpers.EscapeSpecialCharacters(key.Value) + "\r\n");
                }
            }
            return text.ToString();
        }

        /// <summary>
        /// Creates ConfigurationFile object filled with data from a specified file
        /// </summary>
        /// <param name="fileName">Name of a file that contains data</param>
        /// <param name="preventEmptySave">If true, empty configuration will not be save and prevents overwriting over existing file.</param>
        /// <param name="backupOnSave">If true, when configuration is saved, backup of existing configuration file is made.</param>
        public ConfigurationFile(string fileName, bool preventEmptySave, bool backupOnSave)
        {
            this.m_Sections = new List<Section>();
            this.m_FileName = fileName;
            this.m_PreventEmptySave = preventEmptySave;
            this.m_BackupOnSave = backupOnSave;
            if(this.m_FileName != null && this.m_FileName.Length > 0) {
                string text = "";
                if(FileHelpers.ReadTextFile(this.m_FileName, ref text)) ParseText(text);
            }
        }
        /// <summary>
        /// Creates empty ConfigurationFile object
        /// </summary>
        /// <param name="preventEmptySave">If true, empty configuration will not be save and prevents overwriting over existing file.</param>
        /// <param name="backupOnSave">If true, when configuration is saved, backup of existing configuration file is made.</param>
        public ConfigurationFile(bool preventEmptySave, bool backupOnSave)
            : this("", preventEmptySave, backupOnSave)
        {
        }

        /// <summary>
        /// Creates ConfigurationFile object which contains same sections and values as specifiled ConfigurationFile object
        /// </summary>
        /// <param name="configurationFile">ConfigurationFile object to duplicate</param>
        /// <param name="preventEmptySave">If true, empty configuration will not be save and prevents overwriting over existing file.</param>
        /// <param name="backupOnSave">If true, when configuration is saved, backup of existing configuration file is made.</param>
        public ConfigurationFile(ConfigurationFile configurationFile, bool preventEmptySave, bool backupOnSave)
            : this("", preventEmptySave, backupOnSave)
        {
            foreach(Section section in configurationFile.m_Sections) {
                foreach(Key key in section.Keys) {
                    WriteValue(section.Name, key.Name, key.Value);
                }
            }
        }

        /// <summary>
        /// Loads data from another configuration file
        /// </summary>
        /// <param name="fileName">Name of a file that contains data</param>
        /// <param name="clearData">If true, clears all existing data</param>
        /// <param name="keepOldFileName">If true, keeps old file name associated with ConfigurationFile</param>
        /// <returns>Returns true if data is loaded successfuly</returns>
        public bool LoadFromFile(string fileName, bool clearData, bool keepOldFileName)
        {
            if(clearData) Clear();
            if(keepOldFileName == false) this.m_FileName = fileName;
            string text = "";
            if(FileHelpers.ReadTextFile(fileName, ref text)) {
                ParseText(text);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Saves sections and keys to a file with a name you used to create configuration.
        /// If you did not create ConfigurationFile object with a file name as a parameter method will fail,
        /// instead use a method where you can specify a file name.
        /// </summary>
        /// <param name="buildXml">Specifies if output is in ini or xml format</param>
        /// <param name="indentedXml">If output format is xml it specifies if data should be properly formated for easy reading</param>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save(bool buildXml, bool indentedXml)
        {
            if(this.m_FileName == null || this.m_FileName.Length == 0) return false;
            if(this.m_PreventEmptySave && GetTotalKeyCount() == 0) return false;
            return FileHelpers.SaveTextFile(this.m_FileName, BuildText(buildXml, indentedXml), false, m_BackupOnSave);
        }

        /// <summary>
        /// Saves sections and keys to a file with a name you used to create configuration.
        /// If you did not create ConfigurationFile object with a file name as a parameter method will fail,
        /// instead use a method where you can specify a file name.
        /// If output format is xml it will be properly formated for easy reading
        /// </summary>
        /// <param name="buildXml">Specifies if output is in ini or xml format</param>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save(bool buildXml)
        {
            return Save(buildXml, true);
        }

        /// <summary>
        /// Saves sections and keys to a file with a name you used to create configuration.
        /// If you did not create ConfigurationFile object with a file name as a parameter method will fail,
        /// instead use a method where you can specify a file name.
        /// Output is in ini format.
        /// </summary>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save()
        {
            return Save(false);
        }

        /// <summary>
        /// Saves sections and keys to a file with a specified name.
        /// </summary>
        /// <param name="fileName">Name of a file to be written</param>
        /// <param name="buildXml">Specifies if output is in ini or xml format</param>
        /// <param name="indentedXml">If output format is xml it specifies if data should be properly formated for easy reading</param>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save(string fileName, bool buildXml, bool indentedXml)
        {
            this.m_FileName = fileName;
            return Save(buildXml, indentedXml);
        }

        /// <summary>
        /// Saves sections and keys to a file with a specified name.
        /// If output format is xml it will be properly formated for easy reading
        /// </summary>
        /// <param name="fileName">Name of a file to be written</param>
        /// <param name="buildXml">Specifies if output is in ini or xml format</param>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save(string fileName, bool buildXml)
        {
            this.m_FileName = fileName;
            return Save(buildXml);
        }
        /// <summary>
        /// Saves sections and keys to a file with a specified name.
        /// Output is in ini format.
        /// </summary>
        /// <param name="fileName">Name of a file to be written</param>
        /// <returns>True if successful; otherwise, null</returns>
        public bool Save(string fileName)
        {
            this.m_FileName = fileName;
            return Save();
        }


        /// <summary>
        /// Delete all sections and values
        /// </summary>
        public void Clear()
        {
            foreach(Section section in m_Sections) section.Clear();
            this.m_Sections.Clear();
        }

        /// <summary>
        /// Returns total number of sections
        /// </summary>
        /// <returns>Total number of sections</returns>
        public int GetSectionCount()
        {
            return m_Sections.Count;
        }

        /// <summary>
        /// Returns names of all sections
        /// </summary>
        /// <returns>String array of all section names if successful; otherwise, null</returns>
        public string[] GetSectionNames()
        {
            string[] names = new string[this.m_Sections.Count];
            for(int i = 0; i < this.m_Sections.Count; i++) names[i] = this.m_Sections[i].Name;
            return names;
        }

        /// <summary>
        /// Checks if a section with a specified name exists.
        /// </summary>
        /// <param name="sectionName">Name of a section to check if it exists</param>
        /// <returns>True if sections exists; otherwise, false</returns>
        public bool SectionExists(string sectionName)
        {
            return (GetSection(sectionName) != null);
        }

        /// <summary>
        /// Add new section.
        /// </summary>
        /// <param name="sectionName">Name of section to add.</param>
        /// <returns>True if new section is added; otherwise, false</returns>
        public bool AddSection(string sectionName)
        {
            Section section = GetSection(sectionName);
            if(section == null) {
                CreateSection(sectionName);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Delete section with a specified name and all it's keys
        /// </summary>
        /// <param name="sectionName">Name of a section to delete</param>
        /// <returns>True if successful; otherwise, false</returns>
        public bool DeleteSection(string sectionName)
        {
            Section section = GetSection(sectionName);
            if(section != null) {
                section.Clear();
                this.m_Sections.Remove(section);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Returns total number of keys in a section with a specified name
        /// </summary>
        /// <param name="sectionName">Name of a section</param>
        /// <returns>Total number of keys if section exists; otherwise, 0</returns>
        public int GetSectionKeyCount(string sectionName)
        {
            Section section = GetSection(sectionName);
            if(section == null) return 0;
            return section.Keys.Count;
        }

        /// <summary>
        /// Returns names of all keys of specified section.
        /// </summary>
        /// <param name="sectionName">Name of a section</param>
        /// <returns>String array of all key names if successful; otherwise, null</returns>
        public string[] GetSectionKeyNames(string sectionName)
        {
            Section section = GetSection(sectionName);
            if(section != null) return section.GetKeyNames();
            return null;
        }

        /// <summary>
        /// Checks if a key with a specified name exists in a section with specified name.
        /// </summary>
        /// <param name="sectionName">Name of a section</param>
        /// <param name="keyName">Name of a key</param>
        /// <returns>True if key and sections exists; otherwise, false</returns>
        public bool KeyExists(string sectionName, string keyName)
        {
            return (GetKey(sectionName, keyName) != null);
        }

        /// <summary>
        /// Delete key with a specified name in a section with a specified name.
        /// </summary>
        /// <param name="sectionName">Name of a section</param>
        /// <param name="keyName">Name of a value</param>
        /// <returns>True if successful; otherwise, false</returns>
        public bool DeleteKey(string sectionName, string keyName)
        {
            Section section = GetSection(sectionName);
            if(section != null) return section.DeleteKey(keyName);
            return false;
        }



        public bool GetValue(string sectionName, string keyName, bool defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return (ConversionHelpers.StringToInteger(key.Value, 0) == 0) ? false : true;
        }
        public int GetValue(string sectionName, string keyName, int defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToInteger(key.Value, defaultValue);
        }
        public long GetValue(string sectionName, string keyName, long defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToLong(key.Value, defaultValue);
        }
        public uint GetValue(string sectionName, string keyName, uint defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToUnsignedInteger(key.Value, defaultValue);
        }
        public ulong GetValue(string sectionName, string keyName, ulong defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToUnsignedLong(key.Value, defaultValue);
        }
        public float GetValue(string sectionName, string keyName, float defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToFloat(key.Value, defaultValue);
        }
        public double GetValue(string sectionName, string keyName, double defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return ConversionHelpers.StringToDouble(key.Value, defaultValue);
        }
        public string GetValue(string sectionName, string keyName, string defaultValue)
        {
            Key key = GetKey(sectionName, keyName);
            if(key == null || key.Value == null || key.Value.Length == 0) return defaultValue;
            return key.Value;
        }
        public Font GetValue(string sectionName, string keyName, Font defaultValue)
        {
            string fontName = GetValue(sectionName, keyName + ".Name", "");
            float fontSize = GetValue(sectionName, keyName + ".Size", 0f);
            if(fontName.Length > 0 && fontSize > 0) {
                FontStyle fontStyle = FontStyle.Regular;
                if(KeyExists(sectionName, keyName + ".Bold")) fontStyle |= FontStyle.Bold;
                if(KeyExists(sectionName, keyName + ".Italic")) fontStyle |= FontStyle.Italic;
                if(KeyExists(sectionName, keyName + ".Underline")) fontStyle |= FontStyle.Underline;
                return new Font(fontName, fontSize, fontStyle);
            }
            return defaultValue;
        }
        public Point GetValue(string sectionName, string keyName, Point defaultValue)
        {
            if(KeyExists(sectionName, keyName + ".X") && KeyExists(sectionName, keyName + ".Y"))
                return new Point(
                    GetValue(sectionName, keyName + ".X", 0), 
                    GetValue(sectionName, keyName + ".Y", 0)
                    );
            return defaultValue;
        }
        public Size GetValue(string sectionName, string keyName, Size defaultValue)
        {
            if(KeyExists(sectionName, keyName + ".Width") && KeyExists(sectionName, keyName + ".Height"))
                return new Size(
                    GetValue(sectionName, keyName + ".Width", 0), 
                    GetValue(sectionName, keyName + ".Height", 0)
                    );
            return defaultValue;
        }
        public Rectangle GetValue(string sectionName, string keyName, Rectangle defaultValue)
        {
            if(KeyExists(sectionName, keyName + ".X") && KeyExists(sectionName, keyName + ".Y") && 
               KeyExists(sectionName, keyName + ".Width") && KeyExists(sectionName, keyName + ".Height"))
                return new Rectangle(
                    GetValue(sectionName, keyName + ".X", 0),
                    GetValue(sectionName, keyName + ".Y", 0),
                    GetValue(sectionName, keyName + ".Width", 0),
                    GetValue(sectionName, keyName + ".Height", 0)
                    );
            return defaultValue;
        }
        public Color GetValue(string sectionName, string keyName, Color defaultValue)
        {
            if(KeyExists(sectionName, keyName)) return Color.FromArgb(GetValue(sectionName, keyName, 0));
            return defaultValue;
        }
        public Margins GetValue(string sectionName, string keyName, Margins defaultValue)
        {
            if(KeyExists(sectionName, keyName + ".Left") && KeyExists(sectionName, keyName + ".Right") && 
               KeyExists(sectionName, keyName + ".Top") && KeyExists(sectionName, keyName + ".Bottom"))
                return new Margins(
                    GetValue(sectionName, keyName + ".Left", 0),
                    GetValue(sectionName, keyName + ".Right", 0),
                    GetValue(sectionName, keyName + ".Top", 0),
                    GetValue(sectionName, keyName + ".Bottom", 0)
                    );
            return defaultValue;
        }


        public bool SetValue(string sectionName, string keyName, bool value)
        {
            return WriteValue(sectionName, keyName, (value ? "1" : "0"));
        }
        public bool SetValue(string sectionName, string keyName, int value)
        {
            return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, long value)
        {
            return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, uint value)
        {
            return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, ulong value)
        {
            return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, int value, bool hexadecimal)
        {
            if(hexadecimal)
                return WriteValue(sectionName, keyName, "0x" + value.ToString("X8"));
            else
                return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, long value, bool hexadecimal)
        {
            if(hexadecimal)
                return WriteValue(sectionName, keyName, "0x" + value.ToString("X16"));
            else
                return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, uint value, bool hexadecimal)
        {
            if(hexadecimal)
                return WriteValue(sectionName, keyName, "0x" + value.ToString("X8"));
            else
                return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, ulong value, bool hexadecimal)
        {
            if(hexadecimal)
                return WriteValue(sectionName, keyName, "0x" + value.ToString("X16"));
            else
                return WriteValue(sectionName, keyName, value.ToString());
        }
        public bool SetValue(string sectionName, string keyName, float value)
        {
            return WriteValue(sectionName, keyName, value.ToString().Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."));
        }
        public bool SetValue(string sectionName, string keyName, double value)
        {
            return WriteValue(sectionName, keyName, value.ToString().Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."));
        }
        public bool SetValue(string sectionName, string keyName, string value)
        {
            return WriteValue(sectionName, keyName, value);
        }
        public bool SetValue(string sectionName, string keyName, Font value)
        {
            if(value != null) {
                return
                    SetValue(sectionName, keyName + ".Name", value.Name) &&
                    SetValue(sectionName, keyName + ".Size", value.Size) &&
                    (value.Bold ? SetValue(sectionName, keyName + ".Bold", true) : true) &&
                    (value.Italic ? SetValue(sectionName, keyName + ".Italic", true) : true) &&
                    (value.Underline ? SetValue(sectionName, keyName + ".Underline", true) : true);
            } else {
                return DeleteKey(sectionName, keyName);
            }
        }
        public bool SetValue(string sectionName, string keyName, Point value)
        {
            if(value != Point.Empty) {
                return 
                    SetValue(sectionName, keyName + ".X", value.X) &&
                    SetValue(sectionName, keyName + ".Y", value.Y);
            } else
                return DeleteKey(sectionName, keyName);
        }
        public bool SetValue(string sectionName, string keyName, Size value)
        {
            if(value != Size.Empty) {
                return 
                    SetValue(sectionName, keyName + ".Width", value.Width) &&
                    SetValue(sectionName, keyName + ".Height", value.Height);
            } else
                return DeleteKey(sectionName, keyName);
        }
        public bool SetValue(string sectionName, string keyName, Rectangle value)
        {
            if(value != Rectangle.Empty) {
                return 
                    SetValue(sectionName, keyName + ".X", value.X) &&
                    SetValue(sectionName, keyName + ".Y", value.Y) &&
                    SetValue(sectionName, keyName + ".Width", value.Width) &&
                    SetValue(sectionName, keyName + ".Height", value.Height);
            } else
                return DeleteKey(sectionName, keyName);
        }
        public bool SetValue(string sectionName, string keyName, Color value)
        {
            if(value != Color.Empty)
                return SetValue(sectionName, keyName, value.ToArgb(), true);
            else
                return DeleteKey(sectionName, keyName);
        }
        public bool SetValue(string sectionName, string keyName, Margins value)
        {
            if(value != null) {
                return 
                    SetValue(sectionName, keyName + ".Left", value.Left) &&
                    SetValue(sectionName, keyName + ".Right", value.Right) &&
                    SetValue(sectionName, keyName + ".Top", value.Top) &&
                    SetValue(sectionName, keyName + ".Bottom", value.Bottom);
            } else
                return DeleteKey(sectionName, keyName);
        }

        public bool DeleteValue(string sectionName, string keyName)
        {
            return DeleteKey(sectionName, keyName);
        }

    }
}
